/*
 * IdentityComonentDefinition.java
 *
 * Created on September 2, 2006, 4:37 PM
 *
 * (C) 2006 R. Alexander Milowski
 */

package org.infoset.component.library;

import java.io.IOException;
import java.net.URI;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.logging.Logger;
import org.infoset.component.Component;
import org.infoset.component.ComponentBase;
import org.infoset.component.ComponentDefinitionBase;
import org.infoset.xml.Child;
import org.infoset.xml.Document;
import org.infoset.xml.Item;
import org.infoset.xml.ItemConstructor;
import org.infoset.xml.ItemDestination;
import org.infoset.xml.Name;
import org.infoset.xml.Parent;
import org.infoset.xml.XMLException;
import org.infoset.xml.util.DocumentDestination;
import org.infoset.xml.util.DocumentSource;

/**
 *
 * @author alex
 */
public class ReplaceComponentDefinition extends ComponentDefinitionBase {
   
   static Logger LOG = Logger.getLogger(ReplaceComponentDefinition.class.getName());
   static Name DOCUMENT_INPUT_PORT = Name.create("source");
   static Name REPLACEMENT_INPUT_PORT = Name.create("replacement");
   static Name RESULT_OUTPUT_PORT = Name.create("result");
   static List<Name> inputs = new ArrayList<Name>();
   static List<Name> outputs = new ArrayList<Name>();
   static {
      inputs.add(DOCUMENT_INPUT_PORT);
      inputs.add(REPLACEMENT_INPUT_PORT);
      outputs.add(RESULT_OUTPUT_PORT);
   }
   
   public class ReplaceComponent extends ComponentBase {
      
      ItemDestination output;
      Document replacement;
      boolean done;
      
      public ReplaceComponent(Name name,String vendor,String version) {
         super(name,vendor,version);
         this.replacement = null;
      }
      
      public void init(Component.Context context)
         throws XMLException
      {
         super.init(context);
         done = false;
      }
      
      public void bindResource(Name port,Document document)
         throws XMLException 
      {
         if (port.equals(DOCUMENT_INPUT_PORT)) {
         } else if (port.equals(REPLACEMENT_INPUT_PORT)) {
            replacement = document;
         } else {
            throw new XMLException("Binding port "+port+" via ItemSource is not supported.");
         }
      }
   
      public void bindResource(Name port,URI location)
         throws XMLException
      {
         if (port.equals(DOCUMENT_INPUT_PORT)) {
         } else if (port.equals(REPLACEMENT_INPUT_PORT)) {
            try {
               replacement = context.getDocumentLoader().load(location);
            } catch (IOException ex) {
               throw new XMLException("Cannot load input document due to I/O error.",ex);
            }
         } else {
            super.bindResource(port,location);
         }
      }
      public void bindOutputPort(Name port,ItemDestination output)
         throws XMLException
      {
         if (port.equals(RESULT_OUTPUT_PORT)) {
            this.output = output;
         } else {
            throw new XMLException("Unknown output port "+port+" on "+name);
         }
      }

      
      public void onStart() 
         throws XMLException
      {
         if (replacement!=null) {
            generateFromDocuments();
         }
      }
      
      void generateFromDocuments() 
         throws XMLException
      {
         if (done) {
            return;
         }
         DocumentSource.generate(replacement,false,output);
         done = true;
      }
      
      public ItemDestination getInputPort(Name port) 
         throws XMLException
      {
         if (port.equals(DOCUMENT_INPUT_PORT)) {
            return new ItemDestination() {
               public void send(Item item) {}
            };
         } else if (port.equals(REPLACEMENT_INPUT_PORT)) {
            return new ItemDestination() {
               public void send(Item item) 
                  throws XMLException
               {
                  if (output!=null) {
                     output.send(item);
                  }
               }
            };
         } else {
            super.getInputPort(port);
         }
         return null;
      }
      
      public void onDocumentInput(Name port,Document document) 
         throws XMLException
      {
         if (port.equals(DOCUMENT_INPUT_PORT)) {
         } else if (port.equals(REPLACEMENT_INPUT_PORT)) {
            DocumentSource.generate(document,false,output);
            done = true;
         } else {
            super.getInputPort(port);
         }
      }
      
   }
   
   
   /** Creates a new instance of IdentityComonentDefinition */
   public ReplaceComponentDefinition(Name name) {
      super(name,null,null,null);
   }
   
   /** Creates a new instance of IdentityComonentDefinition */
   public ReplaceComponentDefinition(Name name,String vendor,String version,URI vendorLocation) {
      super(name,vendor,version,vendorLocation);
   }
   
   public Component newInstance() 
      throws XMLException
   {
      return new ReplaceComponent(getName(),getVendor(),getVersion());
   }
   
   public Collection<Name> getInputs() {
      return inputs;
   }
   
   public Collection<Name> getOutputs() {
      return outputs;
   }

}
